#ifndef RULES_C
#define RULES_C
#include "rules.h"

static unsigned char protocols[] = {PROT_ICMP,PROT_TCP,PROT_UDP,LAST_RULE_PROT};	// Our protocols

static unsigned int fw_config = 0; // firewall config 

static rule_t* rulesPtr = NULL;    // Global variable for rules pointer

static void loadDefaultRules(void){
	rule_t defaultRules[NUM_OF_DEF_RULES] = { { 0 } };
	int i;		
	// construct default rules
	for(i=0;i<NUM_OF_DEF_RULES;i++){
		defaultRules[i].protocol = protocols[i];
		defaultRules[i].src_ip = LOCALHOST;
		defaultRules[i].dst_ip = LOCALHOST;
		defaultRules[i].src_port = PORT_WILDCARD;
		defaultRules[i].dst_port = PORT_WILDCARD;
		defaultRules[i].src_mask = MAX_BITS_MASK;
		defaultRules[i].dst_mask = MAX_BITS_MASK;
		defaultRules[i].action = NF_ACCEPT;
	}	
	// copy rules 
	if(rulesPtr != NULL)
		memcpy(rulesPtr,defaultRules,sizeof(rule_t)*NUM_OF_DEF_RULES);		
	else
		printk("\n rulesPtr is NULL \n");
}



static char checkPermission(rawPacket_t* packet, int inspectData, int *matchedRuleIndex, int *matchedStringIndex){
	rule_t* nextRule = rulesPtr;
	int count = 0;
	int sPort = 0, dPort = 0/*,i*/; 
	// Iterate over rules array to find the correct rule
	while(nextRule->protocol != LAST_RULE_PROT && count < RULE_BASE_ENTRIES){				
		if(nextRule->protocol == packet->protocol){
			if(ntohl(nextRule->src_ip)  == applyMaskToIP(packet->source_ip,nextRule->src_mask)  && 
			   ntohl(nextRule->dst_ip)  == applyMaskToIP(packet->dest_ip,nextRule->dst_mask)){
				sPort = (nextRule->src_port == 0)?1:(ntohs(nextRule->src_port) == packet->source_port)?1:0;
				dPort = (nextRule->dst_port == 0)?1:(ntohs(nextRule->dst_port) == packet->dest_port)?1:0;
				if(sPort && dPort){	
					if(inspectData){		
						// Rule applied for header data check string matching
						*matchedStringIndex = matchString(packet->data,(unsigned int)packet->data_length,nextRule->search_string,(unsigned int)ntohl(nextRule->search_str_len));
					}else{
						*matchedStringIndex = STRING_MATCH_DEFAULT;
					}
					if(*matchedStringIndex != STRING_UNMATCHED){
						/*printk("\n======== data length %d ============\n",packet->data_length);
						for(i= 0;i<packet->data_length;++i){
							printk("%c",packet->data[i]);
						}
						printk("\n======== packet end  ============\n");*/
						*matchedRuleIndex = count;
						return nextRule->action;	
					}
				}
			}
		}
		++nextRule;
		++count;
	}
	// Cannot find any matched rule
	return UNMATCHED_PACKET;
}

static int matchString(char *strData, unsigned int lenData, char *strFind, unsigned int lenSearch){
	unsigned int i = 0, j = 0;
	/*printk("Data\n");
	for(i=0;i<lenData;++i){
		printk("%c",strData[i]);
	}
	printk("\n Search \n");
	for(i=0;i<lenSearch;++i){
		printk("%d",(int)strFind[i]);
	}
	i = 0;*/
	// No search string is accepted anyways
	if(lenSearch == 0){		 
		//printk("Len search 0\n");
		return 0;
	}
	// Search string is larger than length of data
	if(lenSearch > lenData){
		//printk("Data len out of range (lenData,lenSearch) = (%d,%d) \n",lenData,lenSearch);
		return STRING_UNMATCHED;
	}
	// Cannot go out of bounds
	if(lenSearch > SEARCH_STRING_LENGTH){
		lenSearch = SEARCH_STRING_LENGTH;
	}
	// Brute force algorithm
	
	// Try to search for the string
	for(i=0;i<=lenData-lenSearch;++i){
		for(j=0;j<lenSearch && strFind[j] == strData[j+i];++j);
		if(j >= lenSearch){
			// Found a match
			//printk("\n!match found - index:%d !\n",i);
			return i;
		}
	}
	//printk("CANNOT FIND string index \n");
	return STRING_UNMATCHED;
}
	

#endif
